package com.treasure.mall.biz.service.core.integral.impl;

import com.treasure.mall.biz.base.AbstractSearchableCrudService;
import com.treasure.mall.biz.base.SpecificationAndSort;
import com.treasure.mall.biz.dto.BaseSaveDTO;
import com.treasure.mall.biz.dto.BaseSearchDTO;
import com.treasure.mall.biz.dto.condition.integral.IntegralCountCondition;
import com.treasure.mall.biz.entity.integral.IntegralCountPO;
import com.treasure.mall.biz.entity.integral.IntegralCountPO_;
import com.treasure.mall.biz.repository.integral.IntegralCountRepository;
import com.treasure.mall.biz.repository.integral.UserIntegralLogRepository;
import com.treasure.mall.biz.repository.user.UserRepository;
import com.treasure.mall.biz.service.core.integral.IntegralCountService;
import com.treasure.mall.zbq.common.Jsr310Utils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.persistence.criteria.Predicate;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * @author allan
 * @version 1.0.0
 * @date 2020/8/29
 */
@Service
public class IntegralCountServiceImpl extends AbstractSearchableCrudService<IntegralCountPO, Long> implements IntegralCountService {
    @Resource
    private UserIntegralLogRepository logRepository;
    @Resource
    private UserRepository userRepository;

    @Autowired
    protected IntegralCountServiceImpl(IntegralCountRepository repository) {
        super(repository);
    }

    @Override
    protected SpecificationAndSort<IntegralCountPO> specificationAndSort(BaseSearchDTO searchDTO) {
        IntegralCountCondition condition = (IntegralCountCondition) searchDTO;

        Specification<IntegralCountPO> specification = (root, query, cb) -> {
            List<Predicate> predicates = new ArrayList<>();
            if (StringUtils.isNotEmpty(condition.getBeginTime())) {
                LocalDate beginDate = Jsr310Utils.DateTime.of(condition.getBeginTime()).toLocalDate();
                predicates.add(cb.greaterThanOrEqualTo(root.get(IntegralCountPO_.date), beginDate));
            }
            if (StringUtils.isNotEmpty(condition.getEndTime())) {
                LocalDate endDate = Jsr310Utils.DateTime.of(condition.getEndTime()).toLocalDate();
                predicates.add(cb.lessThanOrEqualTo(root.get(IntegralCountPO_.date), endDate));
            }

            return cb.and(predicates.toArray(new Predicate[predicates.size()]));
        };

        Sort sort = new Sort(Sort.Direction.DESC, "date");

        return new SpecificationAndSort<>(specification, sort);
    }

    @Override
    public IntegralCountPO save(BaseSaveDTO saveDTO) {
        return null;
    }

    @Override
    public IntegralCountPO statistics() {
        IntegralCountPO po = new IntegralCountPO();
        po.setDate(LocalDate.now().minusDays(1));

        LocalDateTime now = LocalDateTime.now().minusDays(1);
        LocalDateTime begin = Jsr310Utils.DateTime.startOfDay(now);
        LocalDateTime end = Jsr310Utils.DateTime.lastOfDay(now);

        po.setTotalSending(logRepository.totalSending(begin, end));
        po.setTotalConsume(logRepository.totalConsume(begin, end));
        BigDecimal proportion = BigDecimal.valueOf(po.getTotalConsume())
                .divide(BigDecimal.valueOf(po.getTotalSending()), RoundingMode.HALF_UP)
                .multiply(BigDecimal.valueOf(100)).setScale(2, RoundingMode.HALF_UP);
        po.setProportion(proportion);
        po.setSendingUserCount(logRepository.sendUserCount(begin, end));
        po.setConsumeUserCount(logRepository.consumeUserCount(begin, end));
        po.setTotalHold(userRepository.integralHolding());
        po.setHoldUserCount(userRepository.holdingUserCount());

        return save(po);
    }
}
